#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
#include <fcntl.h>
#include <errno.h>
#include "head.h"

int sockfd = 0;

// 用户菜单
void user_menu(void);
// 菜单
int menu(void);
// 注册程序
void Register(void);
// 登录程序
int Login(void);
/*用户管理菜单*/
int id_menu(void);
/*用户注销函数*/
int delete_user(void);
/*用户改密函数*/
int change_user(void);
// 上传文件
void upload(void);
// 下载文件
void download(void);
// 显示服务器目录和文件
void s_list(void);
// 显示客户端目录和文件
void c_list(void);
// 退出程序
void quit(void);

// 主函数
int main()
{
	printf("[%s] 服务器创建socket...\n", get_time(2));
	sockfd = socket(AF_INET, SOCK_STREAM, 0);
	if (0 > sockfd)
	{
		perror("socket");
		return -1;
	}

	printf("[%s] 准备地址...\n", get_time(2));
	struct sockaddr_in addr = {};
	addr.sin_family = AF_INET;

	addr.sin_port = htons(60000);

	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	socklen_t len = sizeof(addr);

	printf("[%s] 绑定连接服务器...\n", get_time(2));
	if (connect(sockfd, (struct sockaddr *)&addr, len))
	{
		perror("connect");
		return -1;
	}

	user_menu(); // 加载菜单

	close(sockfd);

	return 0;
}

// 用户菜单
void user_menu(void)
{
	for (;;)
	{
		system("clear");
		printf("\t******* TCP文件传输 *******\n");
		printf("\t      1、用户注册\n");
		printf("\t      2、用户登录\n");
		printf("\t      0、退出系统\n");
		printf("\t***************************\n");

		switch (get_cmd('0', '2'))
		{
		case '1':
			Register();
			break;
		case '2':
			if (Login())
			{
				if (menu())
				{
					return;
				}
			}
			break;
		case '0':
			quit();
			return;
		}
	}
}

/*******************************************************************************************************/

// 注册程序
void Register(void)
{
	// char buf[100] = {};
	char Register[20] = "客户端注册";
	User user;
	int *id = (int *)malloc(sizeof(int));

	printf("[%s] 正在注册...\n", get_time(2));
	write(sockfd, Register, strlen(Register) + 1);

	printf("请输入你的注册号(5位有效数字)>");
	scanf("%d", &user.id);
	*id = user.id;
	write(sockfd, id, sizeof(int));

	printf("请输入你的昵称>");
	scanf("%s", user.name);
	getchar();
	write(sockfd, user.name, strlen(user.name) + 1);

	printf("请输入注册密码>");
	scanf("%s", user.passwd);
	getchar();
	write(sockfd, user.passwd, strlen(user.passwd) + 1);

	return;
}

// 登录程序
int Login(void)
{
	User user;
	char buf[100] = {};
	char Login[20] = "客户端登录";
	int *id = (int *)malloc(sizeof(int));

	printf("[%s] 正在登录...\n", get_time(2));
	write(sockfd, Login, strlen(Login) + 1);

	printf("\t请输入您的id号>");
	scanf("%d", &user.id);
	*id = user.id;
	write(sockfd, id, sizeof(int));

	printf("\t请输入您的密码>");
	scanf("%s", user.passwd);
	getchar();
	write(sockfd, user.passwd, strlen(user.passwd) + 1);

	free(id);

	read(sockfd, buf, sizeof(buf));
	if (strncmp(buf, "success", 10) == 0)
	{
		printf("\t****** 登录成功 ******\n");
		return 1;
	}
	else
	{
		printf("\t****** 登录失败 ******\n");
		printf("\t**   按回车键返回   **\n");
		getchar();
		return 0;
	}
}

/*******************************************************************************************************/

// 加载菜单
int menu(void)
{
	for (;;)
	{
		system("clear");
		printf("\t******* TCP文件传输 *******\n");
		printf("\t       1、上传文件\n");
		printf("\t       2、下载文件\n");
		printf("\t       3、查看服务端目录\n");
		printf("\t       4、查看客户端目录\n");
		printf("\t       5、用户管理系统\n");
		printf("\t       0、退出系统\n");
		printf("\t***************************\n");

		switch (get_cmd('0', '5'))
		{
		case '1':
			upload();
			break;
		case '2':
			download();
			break;
		case '3':
			s_list();
			break;
		case '4':
			c_list();
			break;
		case '5':
			if (id_menu() == 0)
			{
				return 0;
			}
			break;
		case '0':
			quit();
			return 1;
		}
	}
}

int id_menu(void)
{
	system("clear");
	printf("\t========用户账户管理系统========\n");
	printf("\t        1、注销用户\n");
	printf("\t        2、修改密码\n");
	printf("\t        0、返    回\n");
	printf("\t==============================\n");

	switch (get_cmd('0', '5'))
	{
	case '1':
		if (delete_user())
		{
			return 0;
		}
		return 1;
	case '2':
		change_user();
		return 1;
	case '0':
		return 1;
	}
}

/*用户注销函数*/
int delete_user(void)
{
	system("clear");
	char buf[100];
	char delete[20] = "客户端注销";

	printf("\t========是否注销当前用户========\n");
	printf("\t        1、注销用户\n");
	printf("\t        0、返   回\n");
	printf("\t================================\n");

	switch (get_cmd('0', '1'))
	{
	case '1':
		printf("[%s] 正在注销...\n", get_time(2));
		write(sockfd, delete, strlen(delete) + 1);
		break;
	case '0':
		return 0;
	}
	read(sockfd, buf, sizeof(buf));
	if (strncmp(buf, "success", 10) == 0)
	{
		printf("\t****** 注销成功 ******\n");
		printf("\t**   按回车键返回   **\n");
		getchar();
		return 1;
	}
	else
	{
		printf("\t****** 注销失败 ******\n");
		printf("\t**   按回车键返回   **\n");
		getchar();
		return 0;
	}
}

/*用户密码修改*/
int change_user(void)
{
	char buf[90];
	char change[90] = "客户端改密";
	write(sockfd, change, strlen(change) + 1);
	char new_passwd[20], new_passwd_1[20];
	printf("\t请输入新密码>");
	scanf("%s", new_passwd);
	getchar();
	write(sockfd, new_passwd, strlen(new_passwd) + 1);

	printf("\t请再次输入新密码>");
	scanf("%s", new_passwd_1);
	getchar();
	write(sockfd, new_passwd_1, strlen(new_passwd_1) + 1);

	read(sockfd, buf, sizeof(buf));
	if (strncmp(buf, "success", 10) == 0)
	{
		printf("\t****** 改密成功 ******\n");
		printf("\t**   按回车键返回   **\n");
		getchar();
		return 1;
	}
	else
	{
		printf("\t****** 改密失败 ******\n");
		printf("\t**   按回车键返回   **\n");
		getchar();
		return 0;
	}
}

// 上传
void upload(void)
{
	char up[20] = "上传文件";
	write(sockfd, up, strlen(up) + 1);

	// 打印当前目录文件
	c_list();

	int r_size = 0;
	int w_size = 0;
	char buf[1024] = {};
	char buf2[20] = {};
	r_size = read(sockfd, buf, sizeof(buf));
	if (strncmp(buf, "success", 10) != 0)
	{
		printf("[%s] 收到服务端异常数据\n", get_time(2));
		getch();
		return;
	}

	char pathname[100] = {};
	char *filename = malloc(50);
	memset(filename, 0, 50);
	while (1)
	{
		printf("请输入文件名:");
		get_str(pathname, 100);
		if (!strncmp(pathname, "..", 3) || !strncmp(pathname, ".", 3))
		{
			printf(".或..不是普通文件，请重新输入！\n");
			continue;
		}
		break;
	}

	int fd = open(pathname, O_RDONLY);

	if (fd == -1)
	{
		printf("[%s] 文件不存在\n", get_time(2));
		write(sockfd, "error", 6);
		getch();
	}
	else
	{
		write(sockfd, "success", 8);
		r_size = read(sockfd, buf, sizeof(buf));
		if (strncmp(buf, "success", 8) == 0)
		{
			printf("[%s] 服务端已经可以接收文件名，准备发送文件名\n", get_time(2));
		}

		if (strrchr(pathname, '/') == NULL)
		{
			strncpy(filename, pathname, 50);
		}
		else
		{
			filename = strrchr(pathname, '/');
			filename += 1;
		}

		printf("[%s] 发送文件名:%s 至服务端\n", get_time(2), filename);
		write(sockfd, filename, strlen(filename) + 1);


		r_size = 0;

		memset(buf, 0, sizeof(buf));
		r_size = read(sockfd, buf, sizeof(buf));
		if (strncmp(buf, "success", 10) != 0)
		{
			printf("[%s] 收到服务端异常数据\n", get_time(2));
			getch();
			return;
		}
		else
		{
			printf("[%s] 收到服务端返回success，可以开始文件传输\n", get_time(2));
		}

		sleep(1);

		memset(buf, 0, sizeof(buf));
		snprintf(buf, 150, "ls -ll %s | awk '{print $5}'", pathname);
		FILE *temp_fp = NULL;
		temp_fp = popen(buf, "r");
		if (temp_fp == NULL)
		{
			printf("[%s] 获取文件大小失败\n", get_time(2));
		}
		memset(buf, 0, sizeof(buf));
		fscanf(temp_fp, "%s", buf);
		printf("[%s] 文件大小:%sB\n", get_time(2), buf);
		pclose(temp_fp);
		memset(buf, 0, sizeof(buf));

		// 设置文件读写位置为文件尾部
		lseek(fd, 0, SEEK_END);
		// 获取文件字节数（尾部位置）
		off_t end_pos = lseek(fd, 0, SEEK_CUR);
		// printf("end_pos:%d\n", end_pos);
		// 设置文件读写位置为文件头部
		lseek(fd, 0, SEEK_SET);

		do
		{
			// printf("  进入while循环...\n");
			r_size = read(fd, buf, 1024);


			w_size = write(sockfd, buf, r_size);

			read(sockfd, buf2, sizeof(buf2));
			if (strncmp(buf2, "success", 10) == 0)
			{
				// printf("成功收到服务端返回的success]\n");
			}

			off_t cur_pos = lseek(fd, 0, SEEK_CUR);
			// printf("cur_pos:%d\n", cur_pos);
			if (cur_pos == end_pos && w_size == 1024)
			{
				char end[1] = "\0";
				// printf("[读取文件字节数:1 ");
				w_size = write(sockfd, end, sizeof(end));
				// printf("发送字节数:%d ", w_size);
				read(sockfd, buf2, sizeof(buf2));

				if (strncmp(buf2, "success", 10) == 0)
				{
					printf("成功收到服务端返回的success]\n");
				}
				else
				{
					printf("收到服务端返回的异常数据:%s]\n", buf2);
				}
				break;
			}
		} while (r_size == 1024);

		close(fd);

		char result[20] = {};
		read(sockfd, result, sizeof(result));
		if (strncmp(buf2, "success", 10) == 0)
		{
			printf("[%s] 成功收到服务端返回值:%s,服务器接收文件成功\n", get_time(2), result);
		}
		else if (strncmp(buf2, "error", 10) == 0)
		{
			printf("[%s] 成功收到服务端返回值:%s,服务器接收文件异常\n", get_time(2), result);
		}
		else
		{
			printf("[%s] 收到服务端返回值:%s,数据异常\n", get_time(2), result);
		}

		getch();
	}

	return;
}

// 下载
void download(void)
{
	int r_size = 0;
	int w_size = 0;
	char buf[1024] = {};
	char filename[50] = {};
	char list[1024] = {};
	char down[20] = "下载文件";
	write(sockfd, down, strlen(down) + 1);

	r_size = read(sockfd, buf, sizeof(buf));
	if (strncmp(buf, "success", 10) != 0)
	{
		printf("[%s] 收到服务端异常数据\n", get_time(2));
		getch();
		return;
	}
	else
	{
		printf("[%s] 服务端成功接收命令\n", get_time(2));
	}

	// 发送给服务端success，告知可以开始目录列表的发送
	write(sockfd, "success", 8);
	read(sockfd, list, sizeof(list));
	printf("服务端目录列表:%s\n", list);


	while (1)
	{
		printf("请输入要下载的文件名:");
		get_str(filename, 50);
		if (!strncmp(filename, "..", 3) || !strncmp(filename, ".", 3))
		{
			printf(".或..不是普通文件，无法下载，请重新输入！\n");
			continue;
		}
		break;
	}
	write(sockfd, filename, strlen(filename) + 1);

	char result[20] = {};
	read(sockfd, result, sizeof(result));
	if (strncmp(result, "success", 8) == 0)
	{
		printf("[%s] 收到服务端发送的数据:%s 文件准备下载\n", get_time(2), result);
	}
	else if (strncmp(result, "error", 8) == 0)
	{
		printf("[%s] 收到服务端发送的数据:%s 文件不存在\n", get_time(2), result);
		getch();
		return;
	}
	else
	{
		printf("[%s] 收到服务端发送的数据:%s 数据异常,下载终止\n", get_time(2), result);
		getch();
		return;
	}

	int fd = open(filename, O_CREAT | O_RDWR, 0777);

	do
	{
		memset(buf, 0, sizeof(buf));
		r_size = read(sockfd, buf, sizeof(buf));
		// printf("[收到字节数:%d ", r_size);
		w_size = write(fd, buf, r_size);
		// printf("写入文件字节数:%d ", w_size);
		w_size = write(sockfd, "success", 8);
		// printf("发送success给服务端]\n");
	} while (r_size == 1024);
	usleep(10000); // 用户加钱后升级权限，权限越高usleep越低
	printf("[%s] 文件:%s 下载完毕\n", get_time(2), filename);
	close(fd);
	getch();
	return;
}

// 服务端文件列表
void s_list(void)
{
	char see[20] = "查看目录";
	write(sockfd, see, strlen(see) + 1);

	char list[1024] = {};
	read(sockfd, list, sizeof(list));
	printf("服务端目录列表: %s\n", list);

	char cmd[50] = {};

	snprintf(cmd, 20, "...");
	write(sockfd, cmd, strlen(cmd));
	getch();

	return;
}

// 客户端文件列表
void c_list(void)
{
	printf("当前目录列表:");
	DIR *dir;
	dir = opendir(".");
	struct dirent *dirent;
	while ((dirent = readdir(dir)) != NULL)
	{
		printf(" %s ", dirent->d_name);
	}
	printf("\n");
	closedir(dir);
	getch();
	return;
}

// 退出程序
void quit(void)
{
	// char buf[100] = {};
	char quit[20] = "客户端退出";
	write(sockfd, quit, strlen(quit) + 1);

	usleep(100000);

	printf("[%s] 程序退出\n", get_time(2));
	return;
}
